Skip to content

Fix issues with learner record api#3600

Merged
annagav merged 5 commits into
mainfrom
ag/learner_record_api
May 27, 2026
Merged

Fix issues with learner record api#3600
annagav merged 5 commits into
mainfrom
ag/learner_record_api

Conversation

@annagav
Copy link
Copy Markdown
Contributor

@annagav annagav commented May 21, 2026

What are the relevant tickets?

Fix https://github.com/mitodl/hq/issues/10918

Description (What does it do?)

Fix issues with learner record api

How can this be tested?

  1. Create partner school
    Go to http://mitxonline.odl.local:8013/api/records/program/2/ and verify the under "partner_schools" email field is not there.

  2. Make sure you can't view your program record if you don't have an enrollment

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 21, 2026

OpenAPI Changes

Show/hide ## Changes for v0.yaml:
## Changes for v0.yaml:
22 changes: 12 error, 10 warning, 0 info
error	[response-required-property-removed] at head/openapi/specs/v0.yaml
	in API GET /api/records/program/{id}/
		removed the required property `partner_schools/items/created_on` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v0.yaml
	in API GET /api/records/program/{id}/
		removed the required property `partner_schools/items/email` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v0.yaml
	in API GET /api/records/program/{id}/
		removed the required property `partner_schools/items/updated_on` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v0.yaml
	in API POST /api/records/program/{id}/revoke/
		removed the required property `partner_schools/items/created_on` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v0.yaml
	in API POST /api/records/program/{id}/revoke/
		removed the required property `partner_schools/items/email` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v0.yaml
	in API POST /api/records/program/{id}/revoke/
		removed the required property `partner_schools/items/updated_on` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v0.yaml
	in API POST /api/records/program/{id}/share/
		removed the required property `partner_schools/items/created_on` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v0.yaml
	in API POST /api/records/program/{id}/share/
		removed the required property `partner_schools/items/email` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v0.yaml
	in API POST /api/records/program/{id}/share/
		removed the required property `partner_schools/items/updated_on` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v0.yaml
	in API GET /api/records/shared/{uuid}/
		removed the required property `partner_schools/items/created_on` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v0.yaml
	in API GET /api/records/shared/{uuid}/
		removed the required property `partner_schools/items/email` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v0.yaml
	in API GET /api/records/shared/{uuid}/
		removed the required property `partner_schools/items/updated_on` from the response with the `200` status

warning	[response-optional-property-removed] at head/openapi/specs/v0.yaml
	in API GET /api/records/program/{id}/
		removed the optional property `partner_schools/items/is_active` from the response with the `200` status

warning	[response-optional-property-removed] at head/openapi/specs/v0.yaml
	in API POST /api/records/program/{id}/revoke/
		removed the optional property `partner_schools/items/is_active` from the response with the `200` status

warning	[request-property-removed] at head/openapi/specs/v0.yaml
	in API POST /api/records/program/{id}/share/
		removed the request property `email` (media type: multipart/form-data)

warning	[request-property-removed] at head/openapi/specs/v0.yaml
	in API POST /api/records/program/{id}/share/
		removed the request property `email` (media type: application/x-www-form-urlencoded)

warning	[request-property-removed] at head/openapi/specs/v0.yaml
	in API POST /api/records/program/{id}/share/
		removed the request property `email` (media type: application/json)

warning	[request-property-removed] at head/openapi/specs/v0.yaml
	in API POST /api/records/program/{id}/share/
		removed the request property `is_active` (media type: application/x-www-form-urlencoded)

warning	[request-property-removed] at head/openapi/specs/v0.yaml
	in API POST /api/records/program/{id}/share/
		removed the request property `is_active` (media type: application/json)

warning	[request-property-removed] at head/openapi/specs/v0.yaml
	in API POST /api/records/program/{id}/share/
		removed the request property `is_active` (media type: multipart/form-data)

warning	[response-optional-property-removed] at head/openapi/specs/v0.yaml
	in API POST /api/records/program/{id}/share/
		removed the optional property `partner_schools/items/is_active` from the response with the `200` status

warning	[response-optional-property-removed] at head/openapi/specs/v0.yaml
	in API GET /api/records/shared/{uuid}/
		removed the optional property `partner_schools/items/is_active` from the response with the `200` status



## Changes for v1.yaml:
22 changes: 12 error, 10 warning, 0 info
error	[response-required-property-removed] at head/openapi/specs/v1.yaml
	in API GET /api/records/program/{id}/
		removed the required property `partner_schools/items/created_on` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v1.yaml
	in API GET /api/records/program/{id}/
		removed the required property `partner_schools/items/email` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v1.yaml
	in API GET /api/records/program/{id}/
		removed the required property `partner_schools/items/updated_on` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v1.yaml
	in API POST /api/records/program/{id}/revoke/
		removed the required property `partner_schools/items/created_on` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v1.yaml
	in API POST /api/records/program/{id}/revoke/
		removed the required property `partner_schools/items/email` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v1.yaml
	in API POST /api/records/program/{id}/revoke/
		removed the required property `partner_schools/items/updated_on` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v1.yaml
	in API POST /api/records/program/{id}/share/
		removed the required property `partner_schools/items/created_on` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v1.yaml
	in API POST /api/records/program/{id}/share/
		removed the required property `partner_schools/items/email` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v1.yaml
	in API POST /api/records/program/{id}/share/
		removed the required property `partner_schools/items/updated_on` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v1.yaml
	in API GET /api/records/shared/{uuid}/
		removed the required property `partner_schools/items/created_on` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v1.yaml
	in API GET /api/records/shared/{uuid}/
		removed the required property `partner_schools/items/email` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v1.yaml
	in API GET /api/records/shared/{uuid}/
		removed the required property `partner_schools/items/updated_on` from the response with the `200` status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml
	in API GET /api/records/program/{id}/
		removed the optional property `partner_schools/items/is_active` from the response with the `200` status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml
	in API POST /api/records/program/{id}/revoke/
		removed the optional property `partner_schools/items/is_active` from the response with the `200` status

warning	[request-property-removed] at head/openapi/specs/v1.yaml
	in API POST /api/records/program/{id}/share/
		removed the request property `email` (media type: application/x-www-form-urlencoded)

warning	[request-property-removed] at head/openapi/specs/v1.yaml
	in API POST /api/records/program/{id}/share/
		removed the request property `email` (media type: multipart/form-data)

warning	[request-property-removed] at head/openapi/specs/v1.yaml
	in API POST /api/records/program/{id}/share/
		removed the request property `email` (media type: application/json)

warning	[request-property-removed] at head/openapi/specs/v1.yaml
	in API POST /api/records/program/{id}/share/
		removed the request property `is_active` (media type: application/x-www-form-urlencoded)

warning	[request-property-removed] at head/openapi/specs/v1.yaml
	in API POST /api/records/program/{id}/share/
		removed the request property `is_active` (media type: application/json)

warning	[request-property-removed] at head/openapi/specs/v1.yaml
	in API POST /api/records/program/{id}/share/
		removed the request property `is_active` (media type: multipart/form-data)

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml
	in API POST /api/records/program/{id}/share/
		removed the optional property `partner_schools/items/is_active` from the response with the `200` status

warning	[response-optional-property-removed] at head/openapi/specs/v1.yaml
	in API GET /api/records/shared/{uuid}/
		removed the optional property `partner_schools/items/is_active` from the response with the `200` status



## Changes for v2.yaml:
22 changes: 12 error, 10 warning, 0 info
error	[response-required-property-removed] at head/openapi/specs/v2.yaml
	in API GET /api/records/program/{id}/
		removed the required property `partner_schools/items/created_on` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v2.yaml
	in API GET /api/records/program/{id}/
		removed the required property `partner_schools/items/email` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v2.yaml
	in API GET /api/records/program/{id}/
		removed the required property `partner_schools/items/updated_on` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v2.yaml
	in API POST /api/records/program/{id}/revoke/
		removed the required property `partner_schools/items/created_on` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v2.yaml
	in API POST /api/records/program/{id}/revoke/
		removed the required property `partner_schools/items/email` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v2.yaml
	in API POST /api/records/program/{id}/revoke/
		removed the required property `partner_schools/items/updated_on` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v2.yaml
	in API POST /api/records/program/{id}/share/
		removed the required property `partner_schools/items/created_on` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v2.yaml
	in API POST /api/records/program/{id}/share/
		removed the required property `partner_schools/items/email` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v2.yaml
	in API POST /api/records/program/{id}/share/
		removed the required property `partner_schools/items/updated_on` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v2.yaml
	in API GET /api/records/shared/{uuid}/
		removed the required property `partner_schools/items/created_on` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v2.yaml
	in API GET /api/records/shared/{uuid}/
		removed the required property `partner_schools/items/email` from the response with the `200` status

error	[response-required-property-removed] at head/openapi/specs/v2.yaml
	in API GET /api/records/shared/{uuid}/
		removed the required property `partner_schools/items/updated_on` from the response with the `200` status

warning	[response-optional-property-removed] at head/openapi/specs/v2.yaml
	in API GET /api/records/program/{id}/
		removed the optional property `partner_schools/items/is_active` from the response with the `200` status

warning	[response-optional-property-removed] at head/openapi/specs/v2.yaml
	in API POST /api/records/program/{id}/revoke/
		removed the optional property `partner_schools/items/is_active` from the response with the `200` status

warning	[request-property-removed] at head/openapi/specs/v2.yaml
	in API POST /api/records/program/{id}/share/
		removed the request property `email` (media type: application/json)

warning	[request-property-removed] at head/openapi/specs/v2.yaml
	in API POST /api/records/program/{id}/share/
		removed the request property `email` (media type: multipart/form-data)

warning	[request-property-removed] at head/openapi/specs/v2.yaml
	in API POST /api/records/program/{id}/share/
		removed the request property `email` (media type: application/x-www-form-urlencoded)

warning	[request-property-removed] at head/openapi/specs/v2.yaml
	in API POST /api/records/program/{id}/share/
		removed the request property `is_active` (media type: multipart/form-data)

warning	[request-property-removed] at head/openapi/specs/v2.yaml
	in API POST /api/records/program/{id}/share/
		removed the request property `is_active` (media type: application/x-www-form-urlencoded)

warning	[request-property-removed] at head/openapi/specs/v2.yaml
	in API POST /api/records/program/{id}/share/
		removed the request property `is_active` (media type: application/json)

warning	[response-optional-property-removed] at head/openapi/specs/v2.yaml
	in API POST /api/records/program/{id}/share/
		removed the optional property `partner_schools/items/is_active` from the response with the `200` status

warning	[response-optional-property-removed] at head/openapi/specs/v2.yaml
	in API GET /api/records/shared/{uuid}/
		removed the optional property `partner_schools/items/is_active` from the response with the `200` status



Unexpected changes? Ensure your branch is up-to-date with main (consider rebasing).

@annagav annagav force-pushed the ag/learner_record_api branch from 846563c to 8f2d52a Compare May 22, 2026 17:36
@cp-at-mit cp-at-mit self-assigned this May 26, 2026
@annagav annagav force-pushed the ag/learner_record_api branch from ae2e738 to 031df19 Compare May 26, 2026 17:33
Comment on lines +636 to +644
def get_enrolled_program_or_404(user, program_id: int) -> Program:
"""Return a program only if the user has an active enrollment for it."""

enrollment = get_object_or_404(
ProgramEnrollment.objects.select_related("program"),
user=user,
program_id=program_id,
)
return enrollment.program
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The get_enrolled_program_or_404 function does not filter for active enrollments, allowing users who have unenrolled from a program to access their records.
Severity: MEDIUM

Suggested Fix

Update the get_object_or_404 call in get_enrolled_program_or_404 to filter out enrollments with a change_status of ENROLL_CHANGE_STATUS_UNENROLLED. This can be achieved by adding ~Q(change_status=ENROLL_CHANGE_STATUS_UNENROLLED) to the query, aligning it with existing enrollment checks.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: courses/views/v1/__init__.py#L636-L644

Potential issue: The new function `get_enrolled_program_or_404` is intended to return a
program only if a user has an active enrollment, as stated in its docstring. However,
the implementation retrieves any `ProgramEnrollment` object, including inactive ones for
users who have unenrolled (where `change_status` is `'unenrolled'`). This allows a user
who has unenrolled from a program to still access and share their learner record via
views like `GetLearnerRecordView` and `LearnerRecordShareView`. This behavior
contradicts the established pattern in the codebase, where other enrollment checks
explicitly filter out unenrolled records.

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's okay

@annagav annagav merged commit 0226033 into main May 27, 2026
10 checks passed
@annagav annagav deleted the ag/learner_record_api branch May 27, 2026 12:31
This was referenced May 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants